package com.ungao.framework.web.context;

import com.ungao.framework.convert.CaseConverter;
import com.ungao.framework.web.annotation.RequestParam;
import com.ungao.framework.web.exception.RequestException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Map;

/**
 * 请求分发类
 *
 * @author vic-ungao
 */
public class MiniDispatcherServlet extends HttpServlet {

    /**
     * 应用上下文
     */
    private WebApplicationContext applicationContext;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            this.doDispatch(request, response);
        } catch (Exception e) {
            response.getWriter().write("500 Exception Detail: \n" + e.getMessage());
        }
    }

    /**
     * 网络请求分发
     *
     * @param request
     * @param response
     * @throws Exception
     */
    private void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String uri = request.getRequestURI();
        String contextPath = request.getContextPath();
        uri = uri.replaceAll(contextPath, "").replaceAll("/+", "/");

        //处理是否存在请求地址
        if (!this.applicationContext.hasUri(uri)) {
            response.getWriter().write("404 Not Found!!");
            return;
        }

        //获取请求地址对应的方法参数
        Map<String, Parameter> parameters = this.applicationContext.getParameters(uri);
        Object[] paramValues = new Object[parameters.size()];
        String[] keys = parameters.keySet().toArray(new String[parameters.size()]);
        for (int index = 0, size = keys.length; index < size; index++) {

            //获取当前参数修饰信息
            String parameterName = keys[index];
            Parameter parameter = parameters.get(parameterName);

            //HttpServletRequest参数
            if (parameter.getType().equals(HttpServletRequest.class)) {
                paramValues[index] = request;
                continue;
            }

            //HttpServletResponse参数
            if (parameter.getType().equals(HttpServletResponse.class)) {
                paramValues[index] = response;
                continue;
            }

            //是否包含RequestParam注解
            if (parameter.isAnnotationPresent(RequestParam.class)) {

                //处理参数验证
                RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
                Object[] objects = request.getParameterMap().get(requestParam.value());
                if (requestParam.required()) {
                    if (objects == null || objects.length == 0) {
                        throw new RequestException(requestParam.value() + " can not to be null");
                    }
                }
                paramValues[index] = objects;

            } else {

                //获取普通参数
                Object[] objects = request.getParameterMap().get(parameterName);
                paramValues[index] = objects[0];
            }

            //指针向后偏移
            index++;
        }

        //获取请求地址对应的方法映射
        Method method = this.applicationContext.getMethod(uri);
        String beanName = CaseConverter.toLowerCase(method.getDeclaringClass().getSimpleName());
        method.invoke(this.applicationContext.getBean(beanName), paramValues);
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        String contextConfigLocation = config.getInitParameter("contextConfigLocation").split(":")[1];
        this.applicationContext = new WebApplicationContext(contextConfigLocation);
    }
}
